"""
提供与FISCO BCOS区块链网络交互的核心功能
"""

import os
import json
from typing import Optional, Dict, Any
from loguru import logger

from app.config.blockchain_config import blockchain_config
from eth_utils import to_checksum_address


class BlockchainService:
    """
    FISCO BCOS区块链服务类
    
    提供与FISCO BCOS区块链网络交互的核心功能
    """
    
    def __init__(self):
        """初始化区块链服务"""
        self.config = blockchain_config
        self.client = None
        self.contract_abi = None
        
        # 验证配置
        if not self.config.validate_config():
            raise ValueError("区块链配置验证失败")
        
        # 初始化客户端
        self._init_client()
        
        # 加载合约ABI
        self._load_contract_abi()
    
    def _init_client(self):
        """初始化FISCO BCOS客户端"""
        try:
            logger.info("正在初始化FISCO BCOS客户端...")
            
            # 动态设置客户端配置
            self._configure_client()
            
            # 延迟导入 BcosClient，确保配置覆盖已完成
            from client.bcosclient import BcosClient
            
            # 初始化客户端
            self.client = BcosClient()
            
            # 测试连接
            version = self.client.getNodeVersion()
            block_number = self.client.getBlockNumber()
            logger.info(f"FISCO BCOS客户端连接成功，节点版本: {version}, 区块高度: {block_number}")
                    
        except Exception as e:
            logger.error(f"初始化FISCO BCOS客户端失败: {e}")
            raise e
    
    def _configure_client(self):
        """配置客户端参数，使用 .env 文件中的配置覆盖默认配置"""
        try:
            # 导入客户端配置模块
            from client_config import client_config
            
            # 使用 .env 文件中的配置覆盖默认配置
            client_config.channel_host = self.config.channel_host
            client_config.channel_port = self.config.channel_port
            client_config.groupid = self.config.group_id
            client_config.fiscoChainId = self.config.chain_id
            client_config.crypto_type = self.config.crypto_type
            client_config.client_protocol = self.config.client_protocol
            client_config.remote_rpcurl = self.config.remote_rpc_url
            
            # 证书配置 - 使用绝对路径
            if self.config.channel_ca:
                client_config.channel_ca = self.config.get_cert_path(self.config.channel_ca)
            if self.config.channel_node_cert:
                client_config.channel_node_cert = self.config.get_cert_path(self.config.channel_node_cert)
            if self.config.channel_node_key:
                client_config.channel_node_key = self.config.get_cert_path(self.config.channel_node_key)
            if self.config.channel_en_crt:
                client_config.channel_en_crt = self.config.get_cert_path(self.config.channel_en_crt)
            if self.config.channel_en_key:
                client_config.channel_en_key = self.config.get_cert_path(self.config.channel_en_key)
            
            # 账户配置 - 分别设置账户目录和文件名
            if self.config.account_keyfile_path and self.config.account_keyfile:
                # 设置账户目录的绝对路径
                client_config.account_keyfile_path = self.config.get_account_dir_path()
                # 设置账户文件名（不包含路径）
                client_config.account_keyfile = self.config.account_keyfile
            if self.config.account_password:
                client_config.account_password = self.config.account_password
            
            # 合约配置
            if self.config.contract_dir:
                client_config.contract_dir = self.config.contract_dir
            if self.config.contract_info_file:
                client_config.contract_info_file = self.config.contract_info_file
            
            # 日志配置 - 使用包资源管理器获取绝对路径
            client_config.logdir = self.config.get_log_dir_path()
            
            logger.info(f"客户端配置已更新: channel_host={client_config.channel_host}, channel_port={client_config.channel_port}")
            
        except Exception as e:
            logger.error(f"配置客户端参数失败: {e}")
            raise
    
    def _load_contract_abi(self):
        """加载合约ABI"""
        try:
            # 使用包资源管理器加载ABI文件内容
            abi_content = self.config.get_abi_content()
            self.contract_abi = json.loads(abi_content)
            
            logger.info(f"合约ABI加载成功: {self.config.abi_filename}")
            
        except json.JSONDecodeError as e:
            logger.error(f"ABI文件格式错误: {e}")
            raise
        except Exception as e:
            logger.error(f"加载合约ABI失败: {e}")
            raise
    
    def set_greeting(self, greeting: str) -> Optional[str]:
        """
        设置问候语
        
        Args:
            greeting: 要设置的问候语
            
        Returns:
            交易哈希
        """
        try:
            # 构建交易参数
            contract_address = to_checksum_address(self.config.contract_address)
            
            # 发送交易并等待回执
            receipt = self.client.sendRawTransactionGetReceipt(
                to_address=contract_address,
                contract_abi=self.contract_abi,
                fn_name="set",
                args=[greeting]
            )
            
            if receipt and receipt.get("status") == "0x0":
                tx_hash = receipt.get("transactionHash")
                logger.info(f"设置问候语成功: {greeting}, 交易哈希: {tx_hash}")
                return tx_hash
            else:
                logger.error(f"设置问候语失败，交易回执: {receipt}")
                return None
            
        except Exception as e:
            logger.error(f"设置问候语失败: {e}")
            return None
    
    def get_greeting(self) -> Optional[str]:
        """
        获取问候语
        
        Returns:
            当前的问候语
        """
        try:
            # 构建调用参数
            contract_address = to_checksum_address(self.config.contract_address)
            
            # 调用合约的get方法（只读调用）
            result = self.client.call(
                to_address=contract_address,
                contract_abi=self.contract_abi,
                fn_name="get",
                args=[]
            )
            
            if result and len(result) > 0:
                greeting = result[0] if isinstance(result, (list, tuple)) else str(result)
                logger.info(f"获取问候语成功: {greeting}")
                return greeting
            else:
                logger.warning("获取问候语返回空结果")
                return None
            
        except Exception as e:
            logger.error(f"获取问候语失败: {e}")
            return None
    
    def get_transaction_receipt(self, tx_hash: str) -> Optional[Dict[str, Any]]:
        """
        获取交易回执
        
        Args:
            tx_hash: 交易哈希
            
        Returns:
            交易回执
        """
        try:
            receipt = self.client.getTransactionReceipt(tx_hash)
            if receipt:
                logger.info(f"获取交易回执成功: {tx_hash}")
                return receipt
            else:
                logger.warning(f"交易回执不存在: {tx_hash}")
                return None
        except Exception as e:
            logger.error(f"获取交易回执失败: {e}")
            return None
    
    def get_block_number(self) -> Optional[int]:
        """
        获取当前区块高度
        
        Returns:
            区块高度
        """
        try:
            block_number_hex = self.client.getBlockNumber()
            if block_number_hex:
                # 将十六进制转换为十进制
                block_number = int(block_number_hex, 16) if isinstance(block_number_hex, str) else block_number_hex
                logger.info(f"获取区块高度成功: {block_number}")
                return block_number
            else:
                logger.warning("获取区块高度返回空结果")
                return None
        except Exception as e:
            logger.error(f"获取区块高度失败: {e}")
            return None
    
    def is_connected(self) -> bool:
        """
        检查客户端连接状态
        
        Returns:
            连接状态
        """
        try:
            # 尝试获取节点版本来测试连接
            version = self.client.getNodeVersion()
            return version is not None
        except Exception as e:
            logger.error(f"检查连接状态失败: {e}")
            return False
    
    def get_client_info(self) -> Dict[str, Any]:
        """
        获取客户端信息
        
        Returns:
            客户端信息
        """
        try:
            info = {
                "client_type": "BcosClient",
                "is_connected": self.is_connected(),
                "config": {
                    "contract_address": self.config.contract_address,
                    "contract_name": self.config.contract_name,
                    "group_id": self.config.group_id,
                    "chain_id": self.config.chain_id
                }
            }
            
            try:
                info["node_version"] = self.client.getNodeVersion()
                info["block_number"] = self.get_block_number()
            except:
                pass
            
            return info
        except Exception as e:
            logger.error(f"获取客户端信息失败: {e}")
            return {"error": str(e)}


# 全局服务实例
blockchain_service = BlockchainService()